第 5 章  ·  向量数据库(一)- 核心算法

第5章 第5节 向量数据库(一)- 核心算法


第5章 第5节 向量数据库(一)- 核心算法

阅读指南

上一节学会了通过 API 获取 Embedding 向量——给文字贴上了"语义坐标"。但有了向量之后呢?

假设知识库里有成千上万条文档,每条都变成了高维向量。用户提一个问题,需要从海量向量中找出最相关的几条。一个个比对效率极低。这一节解决的就是这个核心问题。


5.1 为什么需要向量数据库

从一个真实场景说起。

一个现实的难题

假设做一个企业知识库问答系统。先看数据规模:

现在用户问:"年假怎么申请?"

系统需要做什么?

  1. 把这个问题也转成向量
  2. 在10万个向量中找到最相似的5个
  3. 把这5个片段交给大模型,让它生成答案

第2步是关键。怎么在10万个向量里快速找到最相似的那5个?

朴素方法的困境

最直接的想法是什么?"暴力搜索"——一个个比对。

# 伪代码:朴素的相似度搜索
question_vec = get_embedding("年假怎么申请?")

similarities = []
for i, doc_vec in enumerate(all_100k_vectors):
    # 计算余弦相似度
    sim = cosine_similarity(question_vec, doc_vec)
    similarities.append((sim, i))

# 排序,取前5个
top_5 = sorted(similarities, reverse=True)[:5]

这段代码有什么问题?

算笔账:

2-3秒什么概念?想想这些场景:

在真实的生产环境中,这个问题会被成倍放大:

这就是为什么需要向量数据库。

5.2 向量数据库的价值

向量数据库做了件很聪明的事:它不会每次都傻傻地遍历所有向量,而是提前把向量组织成特殊的数据结构,让检索可以"跳着走"。

打个比方。

朴素搜索 = 在字典里逐页翻查

要找"Apple"这个词
从第1页开始,一页页翻,直到找到
结果:翻了100页才找到

向量数据库 = 用索引和目录

要找"Apple"

  1. 看首字母索引 → 直接跳到"A"开头的部分
  2. 看第二个字母 → 跳到"Ap"
  3. 看第三个字母 → 定位到"App"
  4. 找到"Apple"
    翻页次数:只需3-5次

这不是快一点点,是快到离谱。向量数据库的核心优势就在这:


5.3 向量数据库的工作原理

向量数据库的核心技术叫近似最近邻搜索(Approximate Nearest Neighbor,ANN)。名字听起来有点拗口,但思想很简单。

核心思想:空间分区

最好理解的方法就是"空间分区"——把向量空间划分成多个区域,查询时只需要在最相关的几个区域里搜索。

用生活中的例子来理解。

5.4 类比:在体育场找人

想象在一个能容纳10万人的体育场里,要随便找到一位穿红色衣服的观众。怎么找?

暴力搜索

从第1排第1座开始,按座位顺序一个个检查每个人的衣服颜色,
直到终于遇到一位穿红衣服的观众。
如果平均检查每个人需要 1 秒,想靠这种方式查一遍,这得看运气,最长需要30个小时左右。

分区搜索(IVF 的思路)

  1. 先把体育场划分成100个看台区域;
  2. 快速扫一眼每个区域的大致颜色分布,
    找出"红衣服明显更多"的3个区域;
  3. 只在这3个区域里逐排逐座细查。
    这样只需要仔细检查几千个人,耗时从"几个小时"降到"几十分钟"。

图搜索(HNSW 的思路)

  1. 从体育场入口的引导员开始打听;
  2. 引导员说:"我刚才看到A区红衣服比较多,去A区问问";
  3. 到了A区后,当地引导员再指"A3看台那一片红衣服最多";
  4. 走到A3,看台管理员直接指"就在这边第5排";
  5. 几分钟内,就锁定到了那一小撮红衣服观众中的一位。
    整个过程只和少数几个"关键节点"打了交道,而不是亲自看过10万人。

向量数据库就是用类似的思想,把高维空间中的向量组织起来。下面看三种主流的索引算法。了解即可。

5.5 IVF(倒排文件索引)

核心思想:聚类 + 倒排

第1步:聚类

图示:

向量空间(简化为2D平面):

          簇3                     簇1
         ★                       ●
      ★  ★  ★               ● ●
    ★  ★中心 ★              ●  ●中心 ●
      ★  ★                   ● ●
        ★                       ●


            簇4                簇2
           ■                  ▲
        ■  ■                ▲ ▲
      ■  ■中心 ■           ▲  ▲中心 ▲
        ■  ■                ▲ ▲
           ■                  ▲

解读:

第2步:查询

用一个示例来理解。假设要找"Python 语言怎么样?"的相关内容:

步骤1:计算查询向量到所有1000个簇中心的距离
簇1(编程语言): 距离 = 0.2 ← 最近
簇2(美食菜谱): 距离 = 0.9
簇3(旅游攻略): 趻离 = 0.85
...
簇15(技术教程): 距离 = 0.18 ← 最近
...

步骤2:选择最近的10个簇
簇15(技术教程)、簇1(编程语言)、簇8(软件开发)...
这些簇共有 1000 个向量

步骤3:只在这 1000 个向量中搜索
找到:

结果:返回这 3 条相关内容

5.6 HNSW(层次化可导航小世界图)

核心思想:多层图结构 + 贪婪搜索

HNSW把向量组织成一个多层的图结构。

整体结构

第2层(稀疏):只有少数节点
    A --------------------------- D

第1层(中等):节点增多
    A ------- B ------- D
              |         |
              C ------- E

第0层(密集):包含所有节点
    A - B - D - F
    |   |   |   |
    H - C - E - G

查询流程

查找示例

假设要找"Python 数据分析"的相关内容

步骤1:第2层(稀疏,只有10个点)
当前在入口点 A

步骤2:第1层(中等,有50个点)
当前在点 D

步骤3:第0层(密集,所有100个点)
当前在点 E

结果:找到 G - "Python数据分析教程"

上述流程最终能找到最相似的"邻近"向量,但不只想找1个"最"相近的,而是想找多个相近的(Top-K)向量。 比如如果要找 Top-5 最相似的结果,那按照上述的流程做5遍吗?并不是。真正的方法如下:

Note

向量怎么分层?

上述图的查找方法,是建立在分层的基础上。一堆向量是怎么分层的?
有兴趣可以阅读下。

其实很简单,完全是随机分层的。

HNSW 建索引时,每个向量都会随机分配一个“层级”:

具体例子:

为什么要随机?

这样设计的好处:

5.7 ■ 学点英语

中文 English 音标 说明
近似近邻 Approximate Nearest Neighbor (ANN) /əˈprɑːksɪmət ˈnɪərəst ˈneɪbər/ 通过索引结构牺牲少量精度换取极快检索速度的算法
精确近邻 K-Nearest Neighbor (KNN) /keɪ ˈnɪərəst ˈneɪbər/ 遍历全部数据确保返回最精确的Top-K结果
倒排文件索引 Inverted File Index (IVF) /ɪnˈvɜːrtɪd faɪl ˈɪndeks/ 通过聚类将向量空间分区,只搜索最近簇的索引方法
分层可导航小世界图 Hierarchical Navigable Small World (HNSW) /ˌhaɪəˈrɑːrkɪkl ˈnævɪɡəbl smɔːl wɜːrld/ 基于多层图结构的近似搜索算法,查询极快
Voronoi 单元 Voronoi Cell /vəˈroʊnɔɪ sel/ IVF聚类后向量空间被划分成的区域,查询时搜索最近单元

5.8 ■ 思考帧

Embedding:把文字变成向量 向量数据库(二)-进阶算法与Chroma实战
本节目录